#include "pm.h"
#include <minix/callnr.h>
#include <signal.h>
#include <sys/svrctl.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <minix/com.h>
#include <minix/config.h>
#include <minix/sysinfo.h>
#include <minix/type.h>
#include <minix/vm.h>
#include <string.h>
#include <machine/archtypes.h>
#include <lib.h>
#include <assert.h>
#include "mproc.h"
#include "param.h"
#include <stdio.h>

typedef struct Process {
	pid_t proc_nr;
} Process;

typedef struct Semaphore {
	int id;
	int value;
	Process processes[20];
	int numProc;
} Semaphore;

Semaphore sems[100];

int numOfSema = 0;
int recentSemaId = 0;

int do_seminit()
{
    int sem = m_in.m1_i1;
    int value = m_in.m1_i2;

	if(numOfSema == 100) {
		return EAGAIN;
	}
	
	if(sem < 0) {
		return EINVAL;
	}

	if(1000 < value || -1000 > value) {
		return EINVAL;
	}

	if(sem == 0) {
		sems[numOfSema].id = recentSemaId + 1;
		sems[numOfSema].value = value;
		sems[numOfSema].numProc = 0;
		numOfSema++;
		recentSemaId++;
	}
	else {
		int i;
		for(i = 0; i < 100; i++) {
			if(sems[i].id == sem){
				return EEXIST;
			}
		}
		sems[numOfSema].id = sem;
		sems[numOfSema].value = value;
		sems[numOfSema].numProc = 0;
		numOfSema++;
		recentSemaId = sem;
	}

    return 0;
}

int do_semfree()
{
    int sem = m_in.m1_i1;
    
	int i;
	for(i = 0; i < 100; i++) {
		if(sems[i].id == sem){
			break;
		}
	}
	
	if(sems[i].numProc == 0) {
		sems[i].id = 0;
		sems[i].value = 0;
	}
	else {
		return EBUSY;
	}	
	
    return 0;
}

int do_semdown()
{
    int sem = m_in.m1_i1;
    
	int i;
	for(i = 0; i < 100; i++) {
		if(sems[i].id == sem){
			break;
		}
	}
	
	sems[i].value--;
	if(sems[i].value < 0) {
		int numOfProc = sems[i].numProc;
		sems[i].processes[numOfProc].proc_nr = mproc[who_p].mp_pid;
		sems[i].numProc++;

		mp->mp_flags |= PAUSED;
		return(SUSPEND);
	}

    return 0;
}

int do_semup()
{
    int sem = m_in.m1_i1;
	
	int i;
	for(i = 0; i < 100; i++) {
		if(sems[i].id == sem){
			break;
		}
	}
	
	sems[i].value++;
	if(sems[i].value < 1) {
		int rmp;
		for(rmp = 0; rmp < NR_PROCS; rmp++) {
			if(mproc[rmp].mp_pid == sems[i].processes[0].proc_nr) {
				break;
			}
		}
		
		int result = ENOSYS;
		
		setreply(rmp, result);
		
		if(sems[i].numProc > 0) {
			int numOfProc = sems[i].numProc;
			sems[i].processes[0].proc_nr = sems[i].processes[numOfProc - 1].proc_nr;
			sems[i].processes[numOfProc - 1].proc_nr = 0;
			sems[i].numProc--;
		}
	}

    return 0;
}

int do_semvalue()
{
    int sem = m_in.m1_i1;
	
	int i;
	for(i = 0; i < 100; i++) {
		if(sems[i].id == sem){
			break;
		}
	}

	mp->mp_reply.reply_res2 = sems[i].value;

    return 0;
}
